package com.oak.broke.websocket.rag;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.oak.broke.constant.WebSocketConstants;
import com.oak.broke.exception.BusinessException;
import com.oak.broke.exception.VipException;
import com.oak.broke.websocket.WebSocketRagClientProxyHandler;
import com.oak.broke.websocket.WebSocketSessions;
import jdk.nashorn.internal.runtime.GlobalConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.websocket.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.*;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * Handles establishment and tracking of next 'hop', and
 * copies data from the current session to the next hop.
 */
@Component
@Slf4j
public class WebSocketProxyRagServerHandler extends TextWebSocketHandler {

    @Resource
    private RestTemplate restTemplate;


    @Value("${ws.textMessage.limit}")
    private Integer textSize;
    @Value("${ws.binaryMessage.limit}")
    private Integer binarySize;
    @Value("${ws.retry.count:3}")
    private Integer retryCount;

    /**
     * 建立连接后执行
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("websocket创建连接：sessionId={}", session.getId());
        WebSocketSessions.WEBSOCKET_SESSIONS_RAG.put(session.getId(), session);
        //Ws请求校验转发第三方接口
        wsConnect(session);
    }


    /**
     * 接收pong消息
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
        log.info("接收pong消息：session={}", session.getId());
        super.handlePongMessage(session, message);
        session.sendMessage(new TextMessage(WebSocketConstants.PING));
    }

    /**
     * 接收客户端发消息
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("客户端发送消息：sessionId={}", session.getId());
        String payloadPing = message.getPayload();
        log.info("收到客户端发送的text消息:{}", payloadPing);

        // 获取握手前设置的用户信息
        Map<String, Object> attributes = session.getAttributes();
        Object userInfo = attributes.get(WebSocketConstants.USER_INFO);
        if (ObjectUtil.isEmpty(userInfo)) {
            session.sendMessage(new TextMessage("{\"message\":\"pong\"}"));
            log.error("会话用户信息获取失败");
            throw new BusinessException("会话用户信息获取失败");
        }
        //UapUser uapUser = JSONUtil.toBean(JSONUtil.toJsonStr(userInfo), UapUser.class);


        // 处理ping消息
        if (StringUtils.equals(payloadPing, WebSocketConstants.PING)) {
            // 转发给第三方ws ping消息
            String proxySessionId = WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.get(session.getId());
            WebSocketSession proxySession = WebSocketSessions.WEBSOCKET_SESSIONS_RAG.get(proxySessionId);
            proxySession.sendMessage(new TextMessage(WebSocketConstants.PING));

            session.sendMessage(new TextMessage("{\"message\":\"pong\"}"));
            return;
        }
        // 处理客户端请求
        //WsReq wsReq = JSONUtil.toBean(payloadPing, WsReq.class);
        //wsReq.setUserId(uapUser.getId());

        String uuid = UUID.randomUUID().toString();
        uuid = StrUtil.subPre(uuid, 8);

        //  构建请求参数


        //根据客户端的sessionid 获取到代理sessionId
        String proxySessionId = WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.get(session.getId());
        log.info("转发消息给第三方ws，sessionId={},proxySessionId={}", session.getId(), proxySessionId);

        WebSocketSession proxySession = WebSocketSessions.WEBSOCKET_SESSIONS_RAG.get(proxySessionId);

        log.info("转发消息给第三方ws，wsModelReq={}", JSONUtil.toJsonStr("wsModelReq"));
        proxySession.sendMessage(new TextMessage(JSONObject.toJSONString("wsModelReq")));
        // todo 记录日志和发送的消息

        WebSocketSessions.RAG_WEBSOCKET_SESSIONS_SEND_MAP.put( session.getId(), new HashMap());

    }


    /**
     * 连接网关的第三方ws
     *
     * @param webSocketSession
     * @throws Exception
     */
    private void wsConnect(WebSocketSession webSocketSession) throws Exception {
        long receiveTime = System.currentTimeMillis();
        log.info("接收ws请求时间：{}", receiveTime);

        String url = Objects.requireNonNull(webSocketSession.getUri()).getPath();
        if (StringUtils.isBlank(url)) {
            webSocketSession.sendMessage(new TextMessage("ws请求path参数为空，无法处理"));
            log.error("ws请求path参数为空，无法处理");
            webSocketSession.close();
            return;
        }
        log.info("websocket连接，id={}，path={}", webSocketSession.getId(), Objects.requireNonNull(webSocketSession.getUri()).getPath());

        //// 设置请求头参数
        //Map<String, String> headers = GetWayUtils.wsHeaders(webSocketRagConfig);
        //String wsPath = StrUtil.format("{}{}", webSocketRagConfig.getGatewayAddress(), webSocketRagConfig.getInteractiveUrl());
        //
        //ApiGatewayRequest apiGatewayRequest = new ApiGatewayRequest();
        //apiGatewayRequest.setWebSocketSessionId(webSocketSession.getId());
        //apiGatewayRequest.setHeaders(headers);
        //apiGatewayRequest.setPath(wsPath);
        //ApiGatewayResponse apiGatewayResponse = new ApiGatewayResponse();
        //ApiGatewayResponse apiGatewayResponseResult = null;
        //log.info("ws连接请求参数打印>>>>>>>>>:{}", JSONObject.toJSONString(apiGatewayRequest));
        //try {
        //    //转发ws请求到网关到第三方ws接口
        //    apiGatewayResponseResult = forwardWs(apiGatewayRequest, apiGatewayResponse);
        //    if (apiGatewayResponseResult.getStatusCode() != HttpStatus.SC_OK) {
        //        log.error("转发ws请求到网关发生错误----->", apiGatewayResponseResult.getException());
        //        webSocketSession.sendMessage(new TextMessage("连接第三方ws失败"));
        //        webSocketSession.close();
        //    }
        //} finally {
        //    long returnTime = System.currentTimeMillis();
        //    log.info("网关响应时间：{}", returnTime);
        //    apiGatewayResponseResult.setReceiveTime(receiveTime);
        //    apiGatewayResponseResult.setReturnTime(returnTime);
        //}
    }


    /**
     * 关闭连接
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        log.info("清理session:status={},sessionId={}", status, sessionId);
        if (WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.containsKey(sessionId)) {
            // 获取WS转发的会话id
            String proxySessionId = WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.get(sessionId);
            if (StringUtils.isNotEmpty(proxySessionId)) {
                //关闭转发连接
                WebSocketSessions.WEBSOCKET_SESSIONS_RAG.get(proxySessionId).close();
            }
            WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.remove(sessionId);
            log.info("清理session映射:sessionId={},proxySessionId={}", sessionId, proxySessionId);
        }
        //当前连接会话关闭时，清理session，同时关闭转发连接，清理session
        if (WebSocketSessions.WEBSOCKET_SESSIONS_RAG.containsKey(sessionId)) {
            session.close();
            log.info("当前连接会话关闭时，清理session，同时关闭转发连接，清理session");
            WebSocketSessions.WEBSOCKET_SESSIONS_RAG.remove(sessionId);
            WebSocketSessions.RAG_WEBSOCKET_SESSIONS_SEND_MAP.remove(session.getId());
        }
    }

    /***
     * 转发请求到部署平台gateway
     *
     * @param request
     * @param apiGatewayResponse
     * @return
     */
    //private ApiGatewayResponse forwardWs(ApiGatewayRequest request, ApiGatewayResponse apiGatewayResponse) {
    //    long requestTime;
    //    long responseTime;
    //    try {
    //        // 网关请求头参数
    //        WebSocketHttpHeaders webSocketHttpHeaders = new WebSocketHttpHeaders();
    //        Map<String, String> header = request.getHeaders();
    //        if (CollUtil.isNotEmpty(header)) {
    //            header.forEach(webSocketHttpHeaders::add);
    //        }
    //        //WS转发连接会话建立
    //        requestTime = System.currentTimeMillis();
    //        log.info("ws网关请求三方能力时间：{}", requestTime);
    //        apiGatewayResponse.setRequestTime(requestTime);
    //        // 连接第三方socket
    //        WebSocketSession webSocketSessionSend = getWebSocketSessionWithRetry(request, webSocketHttpHeaders);
    //        if (webSocketSessionSend == null || !webSocketSessionSend.isOpen()) {
    //            throw new RuntimeException("与网关ws连接失败");
    //        }
    //        responseTime = System.currentTimeMillis();
    //        log.info("ws网关收到三方能力响应时间：{},时间差:{}ms", responseTime, responseTime - requestTime);
    //        apiGatewayResponse.setResponseTime(responseTime);
    //        //Ws转发会话缓存，并将会话id放入响应结果中，并将两个会话进行映射
    //        log.info("forwardWs 第三方会话path:{}, 当前ws会话id:{},第三方ws会话id:{}", request.getPath(), request.getWebSocketSessionId(), webSocketSessionSend.getId());
    //        WebSocketSessions.WEBSOCKET_SESSIONS_RAG.put(webSocketSessionSend.getId(), webSocketSessionSend);
    //        String sessionId = request.getWebSocketSessionId();
    //        log.info("forwardWs 客户端与能力session的关系 key:{},value:{}", sessionId, webSocketSessionSend.getId());
    //        WebSocketSessions.WEBSOCKET_SESSIONS_RAG_MAP.put(sessionId, webSocketSessionSend.getId());
    //        WebSocketSessions.WEBSOCKET_SESSIONS_RAG_PROXY_MAP.put(webSocketSessionSend.getId(), sessionId);
    //
    //        apiGatewayResponse.setStatusCode(HttpStatus.HTTP_OK);
    //        return apiGatewayResponse;
    //    } catch (Exception ae) {
    //        responseTime = System.currentTimeMillis();
    //        log.error("调用网关出现错误------->" + ae);
    //        log.info("ws网关收到请求响应时间：{}", responseTime);
    //        apiGatewayResponse.setResponseTime(responseTime);
    //    }
    //    return apiGatewayResponse;
    //}

    /**
     * 连接服务端socket接口
     *
     * @param request
     * @param webSocketHttpHeaders ws请求头信息
     * @return
     */
    //private WebSocketSession getWebSocketSessionWithRetry(ApiGatewayRequest request, WebSocketHttpHeaders webSocketHttpHeaders) {
    //    WebSocketSession webSocketSession = WebSocketSessions.WEBSOCKET_SESSIONS_RAG.get(request.getWebSocketSessionId());
    //    WebSocketSession webSocketSessionSend = null;
    //    StandardWebSocketClient webSocketClient = new StandardWebSocketClient();
    //    Map<String, Object> userProperties = Maps.newHashMap();
    //    //设置链接超时时间 20s
    //    userProperties.put(Constants.IO_TIMEOUT_MS_PROPERTY, "20000");
    //    webSocketClient.setUserProperties(userProperties);
    //    for (int i = 1; i <= retryCount; i++) {
    //        try {
    //            log.info("第{}次连接", i);
    //            Thread.sleep(1500);
    //            // 代理当前ws接口会话，与第三方ws连接
    //            webSocketSessionSend = webSocketClient.doHandshake(new WebSocketRagClientProxyHandler(webSocketSession), webSocketHttpHeaders, new URI(request.getPath())).get(40000, TimeUnit.MILLISECONDS);
    //            log.info("第{}次连接结果：{}", i, webSocketSessionSend.isOpen());
    //        } catch (Exception e) {
    //            log.error("第次发起websocket失败，原因", e);
    //        }
    //        if (webSocketSessionSend != null && webSocketSessionSend.isOpen()) {
    //            break;
    //        }
    //    }
    //    if (webSocketSessionSend != null) {
    //        webSocketSessionSend.setTextMessageSizeLimit(textSize);
    //        webSocketSessionSend.setBinaryMessageSizeLimit(binarySize);
    //    }
    //    return webSocketSessionSend;
    //}


}
